import wx
import wx.xrc
import os
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt


#本程序的UI操作界面是采用wxPython编写，所以需要继承wx.Frame类，并创建类的实例
class MyFrame1(wx.Frame):

    #在构造函数中编写UI界面，并为按钮绑定相应的事件处理函数
    def __init__(self, parent, id=wx.ID_ANY, title=wx.EmptyString, pos=wx.DefaultPosition,
                 size=(800, 600), style=wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL|wx.VSCROLL):
        wx.Frame.__init__(self, parent, id=id, title=title, pos=pos,
                          size=size, style=style)

        #self.colorImg用来保存真彩色图像数组
        self.colorImg=np.ones((256,256))

        #self.grayImg用来保存灰度图的图像数组
        self.grayImg=np.ones((256,256))

        # self.binaryImg用来保存二值图的图像数组
        self.binaryImg=np.ones((256,256))

        #保存直接灰度变换后的图像
        self.logImg=np.ones((256,256))

        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)

        bSizer1 = wx.BoxSizer(wx.VERTICAL)

        bSizer2 = wx.BoxSizer(wx.HORIZONTAL)

        self.m_button1 = wx.Button(self, wx.ID_ANY, u"选择、读取并显示图像", wx.DefaultPosition, wx.DefaultSize, 0)

        self.m_button1.SetBitmapPosition(wx.TOP)
        bSizer2.Add(self.m_button1, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)

        self.m_button2 = wx.Button(self, wx.ID_ANY, u"显示直接灰度变换后的图像", wx.DefaultPosition, wx.DefaultSize, 0)
        bSizer2.Add(self.m_button2, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)

        self.m_button3 = wx.Button(self, wx.ID_ANY, u"绘制灰度图像的直方图", wx.DefaultPosition, wx.DefaultSize, 0)
        bSizer2.Add(self.m_button3, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)

        self.m_button4 = wx.Button(self, wx.ID_ANY, u"绘制灰度变换后的图像直方图", wx.DefaultPosition, wx.DefaultSize, 0)
        bSizer2.Add(self.m_button4, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)

        self.m_button5 = wx.Button(self, wx.ID_ANY, u"绘制均衡化前后的图像直方图", wx.DefaultPosition, wx.DefaultSize, 0)
        bSizer2.Add(self.m_button5, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 5)

        bSizer1.Add(bSizer2, 0, wx.EXPAND, 5)

        bSizer3 = wx.BoxSizer(wx.VERTICAL)

        gSizer1 = wx.GridSizer(0, 2, 0, 0)

        self.m_bitmap1 = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0)
        gSizer1.Add(self.m_bitmap1, 1, wx.ALL | wx.EXPAND, 5)

        self.m_bitmap2 = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0)
        gSizer1.Add(self.m_bitmap2, 1, wx.ALL | wx.EXPAND, 5)

        self.m_bitmap3 = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0)
        gSizer1.Add(self.m_bitmap3, 1, wx.ALL | wx.EXPAND, 5)

        self.m_bitmap4 = wx.StaticBitmap(self, wx.ID_ANY, wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, 0)
        gSizer1.Add(self.m_bitmap4, 1, wx.ALL | wx.EXPAND, 0)

        bSizer3.Add(gSizer1, 1, wx.EXPAND, 5)

        bSizer1.Add(bSizer3, 1, wx.EXPAND, 5)

        self.SetSizer(bSizer1)
        self.Layout()

        self.Centre(wx.BOTH)

        #为相应每个按钮绑定事件处理函数
        self.m_button1.Bind(wx.EVT_BUTTON, self.chooseFile)
        self.m_button2.Bind(wx.EVT_BUTTON, self.logg)
        self.m_button3.Bind(wx.EVT_BUTTON, self.drawGray)
        self.m_button4.Bind(wx.EVT_BUTTON, self.pltLog)
        self.m_button5.Bind(wx.EVT_BUTTON, self.junhenghua)


    # 实现所有事件处理函数

    #选择图像文件并将其读取，然后显示到UI界面上，该方法实现了图像的读取与显示
    def chooseFile(self, event):
        fd = wx.FileDialog(None, "请选择图像文件", os.getcwd(), wildcard="All files (*.*)|*.*",
                           style=wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
        if fd.ShowModal() == wx.ID_OK:
            #windows系统中文件路径分隔符是'\',但是编程语言和Linux下一般都是'/'，所以用正则进行替换
            self.fileName = fd.GetPath().replace('\\','/')
            print(self.fileName)
        curImg=cv.imread(self.fileName)
        height, width = curImg.shape[:2][::-1]
        if height>342 or width>342:
            #等比例缩小图片，不然太大了显示不下
            curImg=cv.resize(curImg,(0,0),fx=0.3,fy=0.3,interpolation=cv.INTER_NEAREST)
        height,width=curImg.shape[:2]
        pic = wx.Bitmap.FromBuffer(width, height, self.BGR2RGB(curImg))
        self.m_bitmap1.SetBitmap(pic)
        np.resize(self.colorImg,(height,width))
        self.colorImg=curImg


    #绘制灰度图像直方图，在Pyhon中可以直接看到画的Plots，但是为了保持统一，
    #我将绘制的直方图图像保存了下来，然后再读取该图像，再渲染到UI界面上
    def drawGray(self, event):
        plt.hist(self.colorImg.ravel(), 256, [0, 256])
        plt.xlim([0, 256])
        plt.savefig("ansGray.png")
        plt.show()
        ans=cv.imread("ansGray.png")
        w, h = ans.shape[:2][::-1]
        ans=cv.resize(ans,(0,0),fx=0.6,fy=0.6,interpolation=cv.INTER_NEAREST)
        w, h = ans.shape[:2][::-1]
        pic = wx.Bitmap.FromBuffer(w, h, self.BGR2RGB(ans))
        self.m_bitmap3.SetBitmap(pic)

    #图像直接灰度变换：对数变换
    def logg(self,event):
        img=self.colorImg.copy()
        outputImg = 42 * np.log(1.0 + img)
        outputImg = np.uint8(outputImg + 0.5)
        height, width = outputImg.shape[:2]
        pic = wx.Bitmap.FromBuffer(width, height, self.BGR2RGB(outputImg))
        self.m_bitmap2.SetBitmap(pic)
        self.logImg=outputImg


    #绘制直接灰度变换后的图像直方图
    def pltLog(self,event):
        plt.hist(self.logImg.ravel(), 256, [0, 256])
        plt.xlim([0, 256])
        plt.savefig("logGray.png")
        plt.show()
        ans = cv.imread("logGray.png")
        w, h = ans.shape[:2][::-1]
        ans = cv.resize(ans, (0, 0), fx=0.6, fy=0.6, interpolation=cv.INTER_NEAREST)
        w, h = ans.shape[:2][::-1]
        pic = wx.Bitmap.FromBuffer(w, h, self.BGR2RGB(ans))
        self.m_bitmap4.SetBitmap(pic)


    #针对单通道的直方图均衡化
    def myEqualizehist(self,single):
        hist = cv.calcHist([single], [0], None, [256], [0, 256])
        num_of_pixels = single.size
        ratio = np.zeros(256)
        transf_map = np.zeros(256)
        result = single.copy()
        j = 0
        for i in hist:
            if j > 0:
                ratio[j] = i / num_of_pixels + ratio[j - 1]
            else:
                ratio[j] = i / num_of_pixels
            transf_map[j] = round(ratio[j] * 255)
            j = j + 1
        for i in range(single.shape[0]):
            for j in range(single.shape[1]):
                result[i][j] = transf_map[single[i][j]]
        return result


    #对直方图进行总体均衡化，并且显示均衡化之前的直方图和均衡后的直方图
    def junhenghua(self,event):
        img=self.logImg.copy()
        plt.hist(self.logImg.ravel(), 256, [0, 256])
        plt.xlim((0, 255))
        plt.savefig("junhenghuaGray.png")
        plt.show()
        window = cv.namedWindow("Orignal Image histogram")
        kk=cv.imread("junhenghuaGray.png")
        cv.imshow("Orignal Image histogram",kk)
        tmpImg=self.logImg.copy()

        B, G, R = cv.split(tmpImg)
        EB = self.myEqualizehist(B)
        EG = self.myEqualizehist(G)
        ER = self.myEqualizehist(R)
        equalTest = cv.merge((EB, EG, ER))
        plt.hist(equalTest.ravel(), 256, [0, 256])
        plt.xlim((0, 255))
        plt.savefig("myjunhenghuaGray.png")
        plt.show()
        window = cv.namedWindow("Equalized image histogram")
        pp = cv.imread("myjunhenghuaGray.png")
        cv.imshow("Equalized image histogram", pp)




    #下面这个函数将BGR图像转换成RGB，因为在opencv中是按bgr的通道顺序，
    #但是在wxPython中的Bitmap是按照rgb的通道顺序，为了在UI界面上显示，
    #所以需要转换
    def BGR2RGB(self,src):
        (B, G, R) = cv.split(src)
        img = cv.merge([R, G, B])
        return img

#主函数，程序的入口
if __name__ == '__main__':
    app=wx.App()
    mainWindow=MyFrame1(None,title="实验二",size=(1200,700))
    mainWindow.Show(True)
    app.MainLoop()


